package me.bincker.formwork.web.modules.system.controller

import me.bincker.formwork.web.entity.ResultPage
import me.bincker.formwork.web.modules.system.entity.User
import me.bincker.formwork.web.modules.system.form.UserForm
import me.bincker.formwork.web.modules.system.service.IUserService
import me.bincker.formwork.web.test.ResultMatchers
import me.bincker.formwork.web.test.TestSession
import me.bincker.formwork.web.test.TestUtils
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.data.domain.PageRequest
import org.springframework.data.domain.Pageable
import org.springframework.http.MediaType
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.test.context.junit4.SpringRunner
import org.springframework.test.web.servlet.ResultActions
import org.springframework.test.web.servlet.result.MockMvcResultHandlers
import org.springframework.test.web.servlet.result.MockMvcResultMatchers
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.context.WebApplicationContext

@SpringBootTest
@RunWith(SpringRunner::class)
class UserControllerTest {
    companion object{
        fun getPage(session: TestSession, pageable: Pageable, user: User? = null): ResultPage<User> {
            val result = session.perform(session.get("/users"))
                    .andExpect(ResultMatchers.IS_OK)
                    .andReturn()
            return TestUtils.deSerialiseJson(result.response.contentAsString)
        }

        fun getOne(session: TestSession, id: String): User{
            val result = session.perform(session.get("/users/{id}", id))
                    .andExpect(ResultMatchers.IS_OK)
                    .andReturn()
            return TestUtils.deSerialiseJson(result.response.contentAsString)
        }

        fun add(session: TestSession, user: User): User{
            val result = session.perform(
                    session.post("/users")
                            .contentType(MediaType.APPLICATION_JSON_UTF8)
                            .content(TestUtils.serialiseJson(user))
            )
                    .andExpect(ResultMatchers.IS_OK)
                    .andReturn()
            return TestUtils.deSerialiseJson(result.response.contentAsString)
        }

        fun put(session: TestSession, user: User): User{
            val result = session.perform(
                    session.put("/users")
                            .contentType(MediaType.APPLICATION_JSON_UTF8)
                            .content(TestUtils.serialiseJson(user))
            )
                    .andDo(MockMvcResultHandlers.print())
                    .andExpect(ResultMatchers.IS_OK)
                    .andReturn()
            return TestUtils.deSerialiseJson(result.response.contentAsString)
        }

        fun changePassword(session: TestSession, id: String, password: String): User{
            val result = session.perform(
                    session.patch("/users/{id}/change-password", id)
                            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                            .param("password", password)
            )
                    .andDo(MockMvcResultHandlers.print())
                    .andExpect(ResultMatchers.IS_OK)
                    .andReturn()
            return TestUtils.deSerialiseJson(result.response.contentAsString)
        }
    }

    @Autowired
    private lateinit var webApplicationContext: WebApplicationContext

    @Autowired
    private lateinit var userService: IUserService

    @Autowired
    private lateinit var passwordEncoder: PasswordEncoder

    @Test
    fun getPage(){
        val session = TestSession(webApplicationContext)
        session.login()
        println(getPage(session, PageRequest.of(0, 20)))
    }

    @Test
    fun getOne(){
        val session = TestSession(webApplicationContext)
        session.login()
        println(getOne(session, "1"))
    }

    @Test
    @Transactional
    fun add(){
        val session = TestSession(webApplicationContext)
        session.login()
        val role = RoleControllerTest.getOne(session, "1")
        val user = UserForm()
        user.username = "bincker"
        user.nickname = "binckerNickname"
        user.password = "123456"
        user.locked = false
        user.phoneNumber = "13845678912"
        user.email = "123456789@qq.com"
        user.gender = User.Companion.Gender.MALE
        user.roleList = mutableSetOf(role)
        println(add(session, user))
    }

    @Test
    @Transactional
    fun put(){
        val session = TestSession(webApplicationContext)
        session.login()
        val user = getOne(session, "1")
        user.nickname = "b i n c k e r"
        user.phoneNumber = "17812345678"
        println(put(session, user))
    }

    @Test
    @Transactional
    fun changePassword(){
        val session = TestSession(webApplicationContext)
        session.login()
        val password = "654321"
        val userId = "1"
        println(changePassword(session, userId, password))
        Assert.assertTrue("修改密码失败", passwordEncoder.matches(password, userService.getOne(userId).encodedPassword))
    }
}